/**
 * Trabalho 2 de Programacao Concorrente.
 * Prof. Dr. Julio Estrella
 * 
 * Determinacao da ocorrencia de palindromos e
 * calculo de numeros primos.
 * 
 * Grupo 07 - Turma B
 * Fabio de Albuquerque Dela Antonio 6792558
 * Leonardo Henrique Omoto 6793160
 * Pedro Paulo Canto Martucci 6793100
 * 
 * main.c
 */

#include "../include/header.h"
#include "../include/palindromo.h"
#include "../include/primo.h"
#include "../include/parser.h"

#ifdef PARALELO
/* Versao paralela (OpenMP + MPI) */
int main(int argc, char *argv[]) {
    
    /* Imprime a saida? */
    int imprime = 0;
    
    /* Variaveis para arquivo. */
    int start, end, tamArq;
    
    /* Variaveis para o problema. */
    int valorPalavra, i=0, j=0, tam, tamfrases;
    char *palavra, **frases, **palavras; 
    int verif; 
    int countPalindromos = 0, countFrasesPalindromos = 0, countPrimos = 0, countFrases = 0, countPalavras = 0;
    int * primos, tamprimos;
    FILE *fp;
    
    /* Variaveis para contagem de tempo. */
    double time_proc_i = 0, time_proc_f, time_proc = 0;

    #ifdef TEMPOS_DETALHADOS
    double time_palin_pala_i = 0, time_palin_pala_f, time_palin_pala = 0;
    double time_palin_frase_i = 0, time_palin_frase_f, time_palin_frase = 0;
    double time_primo_i = 0, time_primo_f, time_primo = 0;
    double time_arq_i = 0, time_arq_f, time_arq = 0;
    #endif
    
    /* Variaveis para paralelismo. */
    int rank , size, tag=999;
    char ** bf;
    int tamaux;
    int tcountPalindromos = 0, tcountFrasesPalindromos = 0, tcountPrimos = 0, tcountFrases = 0, tcountPalavras = 0;
    double ttime_proc;
    char *output;
    char tmp[10000];
    int output_size = 0;
    MPI_Status stats;
    
    #ifdef TEMPOS_DETALHADOS
    double ttime_palin_pala, ttime_palin_frase, ttime_primo, ttime_arq;
    #endif
    
    /* Inicializacao da MPI */
    int mpicheck = MPI_Init(&argc, &argv);
    
    if(mpicheck != MPI_SUCCESS)
        return 1;
        
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);

    /* Verifica argumentos */
    if(argc < 4 || argc > 4) {
        printf("Uso: %s <arquivo de entrada> <metodo de analise> <imprime a saida?>\n", argv[0]);
        printf("<metodo de analise> = 1   --> leitura de palavras\n");
        printf("<metodo de analise> = 2   --> leitura de palavras e frases\n");
        printf("<imprime a saida?> = 1 para imprimir ou 0 para nao imprimir.\n");
        return 1;
    }

    imprime = atoi(argv[3]);
    
    if(imprime != 0 && imprime != 1) {
        fprintf(stderr, "Parametro incorreto para argumento 4.\n");
        MPI_Finalize();
        return 1;
    }

    /* Inicia contagem do tempo. */
    time_proc_i = MPI_Wtime();

    /* Carrega arquivo. */
    fp = fopen(argv[1],"r");

    if(fp == NULL) {
        fprintf(stderr, "Erro na abertura do arquivo. Verifique se o arquivo existe ou se o direitorio esta correto.\n");
        MPI_Finalize();
        return 1;
    }

    if (imprime)
    {
        output = (char *)calloc(OUTPUT_MAX_SIZE,sizeof(char));

        if( output == NULL)
        {
            fprintf(stderr, "Impossivel alocar vetor de saida!\n");
            MPI_Finalize();
            return 1;
        }
    }

    tamArq = (int)fileSize(fp);

    /* Carrega arquivo em memoria principal de uma vez soh (mais rapido do que leituras aos poucos). */
    #ifdef TEMPOS_DETALHADOS
    time_arq_i = MPI_Wtime();
    #endif
    
    char * buffer = (char *)calloc(tamArq+1,sizeof(char));
    
    if(buffer == NULL) {
        fprintf(stderr, "Impossivel alocar copia do arquivo em memoria principal!\n");
        return 1;
    }
    
    fread(buffer, sizeof(char), tamArq, fp);
    
    buffer[tamArq] = '\0';
    
    fclose(fp);
    
    #ifdef TEMPOS_DETALHADOS
    time_arq_f = MPI_Wtime();
    time_arq += time_arq_f - time_arq_i;
    #endif
    
    /* Execucao para modo 1. */
    if(atoi(argv[2]) == 1) {   
        
        /* Calcula intervalos do arquivo... */
        start = (rank)*(tamArq/size);
        if(rank != size) end = (rank+1)*(tamArq/size);
        else end = tamArq;
        
        /* Ajusta ponteiro do arquivo e comeca computacao. */
        if(ajustaPonteiroPalavra(buffer, tamArq, &start, end) == 0) {
            
            #ifdef TEMPOS_DETALHADOS
            time_primo_i = MPI_Wtime();
            #endif
            
            /* Prepara vetor de primos */
            primos = calcPrimos(1000);
            tamprimos = 1000;
            
            #ifdef TEMPOS_DETALHADOS
            time_primo_f = MPI_Wtime();
            time_primo += time_primo_f - time_primo_i;
            
            time_arq_i = MPI_Wtime();
            #endif
            
            /* Gera vetor de ponteiros para strigns contendo as palavras. */
            palavras = parseProxPalavras(buffer, tamArq, &start, end, &tam);

            #ifdef TEMPOS_DETALHADOS
            time_arq_f = MPI_Wtime();
            time_arq += time_arq_f - time_arq_i;
            #endif
            
            do {
                
                tamaux = tam;
                
                /* Faz decomposicao de controle local (com pipeline) */
                #pragma omp parallel private(verif,valorPalavra,i)
                { 
                    
                    #pragma omp sections
                    {
                        
                        /* Preenche ponteiros para palavras (para o próximo bloco)... */
                        #pragma omp section
                        {
                            #ifdef TEMPOS_DETALHADOS
                            time_arq_i = MPI_Wtime();
                            #endif
                            
                            /* Gera vetor de ponteiros para strigns contendo as palavras. */
                            bf = parseProxPalavras(buffer, tamArq, &start, end, &tam);
                            
                            #ifdef TEMPOS_DETALHADOS
                            time_arq_f = MPI_Wtime();
                            time_arq += time_arq_f - time_arq_i;
                            #endif
                        }
                        
                        /* ...Enquanto processa (verifica palindromos e primos) as palavras (do bloco atual). */
                        #pragma omp section
                        {
                            if(tamaux > 0) {
                                
                                /* Faz computacao */
                                for(i = 0; i < tamaux; i++) {
                                    
                                    #ifdef TEMPOS_DETALHADOS
                                    time_palin_pala_i = MPI_Wtime();
                                    #endif
                                    
                                    verif = verificaPalindromo(palavras[i]);
                                    
                                    #ifdef TEMPOS_DETALHADOS
                                    time_palin_pala_f = MPI_Wtime();
                                    time_palin_pala += time_palin_pala_f - time_palin_pala_i;
                                    #endif
                                    
                                    if(verif) {
                                        countPalindromos++;
                                        
                                        #ifdef TEMPOS_DETALHADOS
                                        time_primo_i = MPI_Wtime();
                                        #endif
                                        
                                        valorPalavra = convertePalavraInteiro(palavras[i]);
                                        
                                        verif = verificaPrimo(&primos, &tamprimos, valorPalavra);
                                        
                                        #ifdef TEMPOS_DETALHADOS
                                        time_primo_f = MPI_Wtime();
                                        time_primo += time_primo_f - time_primo_i;
                                        #endif
                                        
                                        if(verif) {
                                            countPrimos++;
                                        }
                                        
                                        if(imprime) {
                                           strcpy(tmp,"");
                                           sprintf(tmp,"%s -- %d %s e primo.\n", palavras[i], valorPalavra, (verif) ? " ":"nao");
                                           if( strlen(tmp) + output_size < OUTPUT_MAX_SIZE ) {
                                               strcat(output,tmp);
                                                output_size += strlen(tmp);
                                           }
                                        }
                                    }
                                    
                                }
                                
                                free(palavras);
                            }
                            
                            countPalavras += tamaux;
                        }
                    }
                }
                
                palavras = bf;
                
            } while(bf != NULL);
            
            free(primos);
        }                
    }
    

    /* Execucao para modo 2. */
    else if(atoi(argv[2]) == 2) {
        
        /* Calcula intervalos do arquivo... */
        start = rank*(tamArq/size);
        if(rank != size) end = (rank+1)*(tamArq/size);
        else end = tamArq;

        /* Ajusta ponteiro do arquivo e comeca computacao. */
        if(ajustaPonteiroFrase(buffer, tamArq, &start, end) == 0) {
            
            #ifdef TEMPOS_DETALHADOS
            time_arq_i = MPI_Wtime();
            #endif
            
            /* Gera vetor de ponteiros para strigns contendo as frases. */
            frases = parseProxFrases(buffer, tamArq, start, end, &tamfrases);

            #ifdef TEMPOS_DETALHADOS
            time_arq_f = MPI_Wtime();
            time_arq += time_arq_f - time_arq_i;
            #endif
            
            countFrases = tamfrases;
            
            if(tamfrases > 0) {
                
                /* Faz decomposicao de dados local */
                #ifdef TEMPOS_DETALHADOS
                #pragma omp parallel private(verif, palavras, palavra, tam, i, j, time_palin_frase_i, time_palin_frase_f, time_palin_pala_i, time_palin_pala_f, time_arq_i, time_arq_f) firstprivate(frases,tamfrases)
                #else
                #pragma omp parallel private(verif, palavras, palavra, tam, i, j) firstprivate(frases,tamfrases)
                #endif
                { 
                    #pragma omp for schedule(runtime)
                    for(i = 0; i < tamfrases; i++) {
                        
                        #ifdef TEMPOS_DETALHADOS
                        time_palin_frase_i = MPI_Wtime();
                        #endif
                        
                        verif = verificaPalindromo(frases[i]);
                        
                        #ifdef TEMPOS_DETALHADOS
                        time_palin_frase_f = MPI_Wtime();
                        
                        #pragma omp critical
                        time_palin_frase += time_palin_frase_f - time_palin_frase_i;
                        #endif
                        
                        if(verif) {
                            #pragma omp critical 
                            countFrasesPalindromos++;
                        }
                        
                        if(verif)
                        {
                            if(imprime) {
                                strcpy(tmp,"");
                                sprintf(tmp, "%s - palindromo frase.\n", frases[i]);
                                if( strlen(tmp) + output_size < OUTPUT_MAX_SIZE ) {
                                    strcat(output,tmp);
                                    output_size += strlen(tmp);
                                }
                                
                            }
                        }
                            
                        /* Copia palavras de uma frase em um vetor de strings. */
                        #ifdef TEMPOS_DETALHADOS
                        time_arq_i = MPI_Wtime(); 
                        #endif
                        
                        palavras = parsePalavraFrase(frases[i], &tam);
                            
                        #ifdef TEMPOS_DETALHADOS
                        time_arq_f = MPI_Wtime();
                        
                        #pragma omp critical
                        time_arq += time_arq_f - time_arq_i;
                        #endif
                        
                        for(j = 0; j < tam; j++) {
                            palavra = palavras[j];
                            
                            #ifdef TEMPOS_DETALHADOS
                            time_palin_pala_i = MPI_Wtime();
                            #endif
                            
                            verif = verificaPalindromo(palavra);
                            
                            #ifdef TEMPOS_DETALHADOS
                            time_palin_pala_f = MPI_Wtime();
                            
                            #pragma omp critical
                            time_palin_pala += time_palin_pala_f - time_palin_pala_i;
                            #endif
                            
                            if(verif) {
                                #pragma omp critical
                                countPalindromos++;
                            }
                                
                            
                            if(verif) {
                                if(imprime) {
                                    strcpy(tmp,"");
                                    sprintf(tmp, "%s -- e palindromo palavra\n", palavras[j]);
                                    if( strlen(tmp) + output_size < OUTPUT_MAX_SIZE ) {
                                        strcat(output,tmp);
                                        output_size += strlen(tmp);
                                    }
                                    
                                }
                            }
                        }
                        
                        #pragma omp critical
                        countPalavras += tam;
                        
                        free(palavras);
                    }   
                }
                free(frases);
            }
        }     
    }

    /* Tempo final */
    time_proc_f = MPI_Wtime();
    time_proc = time_proc_f - time_proc_i;


    /* Caso imprime seja 1, o nó mestre irá esperar pelos resultados dos outros nós para imprimir os resultados */
    if( rank == MASTER && imprime ) 
    {
        printf("%s", output);
        strcpy(output,"");            

        /* Recebimento síncrono de cada parte dos resultados */
        for( i = 1; i < size; i++ )
        {
            MPI_Recv(output, OUTPUT_MAX_SIZE, MPI_CHAR, i, tag, MPI_COMM_WORLD, &stats);
            printf("%s", output);
            strcpy(output,"");
        }
    }
    /* Caso não seja o nó mestre, os resultados serão enviados para ele */
    else if( rank != MASTER && imprime)
    {
        MPI_Send(output, strlen(output)+1, MPI_CHAR, MASTER, tag, MPI_COMM_WORLD);
    }
    
    /* Agrega variaveis locais dos nos nas variaveis compartilhadas. */
    MPI_Reduce(&countFrases,&tcountFrases, 1, MPI_INT, MPI_SUM, MASTER, MPI_COMM_WORLD);
    MPI_Reduce(&countFrasesPalindromos,&tcountFrasesPalindromos, 1, MPI_INT, MPI_SUM, MASTER, MPI_COMM_WORLD);
    MPI_Reduce(&countPalavras,&tcountPalavras, 1, MPI_INT, MPI_SUM, MASTER, MPI_COMM_WORLD);
    MPI_Reduce(&countPalindromos,&tcountPalindromos, 1, MPI_INT, MPI_SUM, MASTER, MPI_COMM_WORLD);
    MPI_Reduce(&countPrimos,&tcountPrimos, 1, MPI_INT, MPI_SUM, MASTER, MPI_COMM_WORLD);
    
    MPI_Reduce(&time_proc,&ttime_proc, 1, MPI_DOUBLE, MPI_SUM, MASTER, MPI_COMM_WORLD);
    
    #ifdef TEMPOS_DETALHADOS
    MPI_Reduce(&time_primo,&ttime_primo, 1, MPI_DOUBLE, MPI_SUM, MASTER, MPI_COMM_WORLD);
    MPI_Reduce(&time_arq,&ttime_arq, 1, MPI_DOUBLE, MPI_SUM, MASTER, MPI_COMM_WORLD);
    MPI_Reduce(&time_palin_pala,&ttime_palin_pala, 1, MPI_DOUBLE, MPI_SUM, MASTER, MPI_COMM_WORLD);
    MPI_Reduce(&time_palin_frase,&ttime_palin_frase, 1, MPI_DOUBLE, MPI_SUM, MASTER, MPI_COMM_WORLD);
    #endif
    
    /* Libera buffer do arquivo na memoria principal. */
    free(buffer);
    
    /* Mestre espera pelos nos escravos depois de terminar sua computacao. */
    if(rank == MASTER) {
        
        /* Calcula media dos tempos. */
        ttime_proc *= 1000.0f/(double)(size);
        
        #ifdef TEMPOS_DETALHADOS
        ttime_primo *= 1000.0f/(double)(size);
        ttime_arq *= 1000.0f/(double)(size);
        ttime_palin_frase *= 1000.0f/(double)(size);
        ttime_palin_pala *= 1000.0f/(double)(size);
        #endif
        
        /* Imprime resultados obtidos... */
        fprintf(stderr, "Resultado\nPalavras processadas: %d\nFrases processadas: %d\nPalindromos encontrados: %d\nPrimos encontrados: %d\nNumero de frases palindromos encontrado: %d\n\nTempo medio total: %lf ms\n", tcountPalavras, tcountFrases, tcountPalindromos, tcountPrimos, tcountFrasesPalindromos, ttime_proc);
        
        #ifdef TEMPOS_DETALHADOS
        fprintf(stderr, "Tempo medio de calculo dos palindromos de palavras: %lf ms\nTempo medio de calculo dos palindromos de frases: %lf ms\nTempo medio de calculo dos primos: %lf ms\nTempo medio do processamento de buffers e arquivos: %lf ms\n", ttime_palin_pala, ttime_palin_frase, ttime_primo, ttime_arq);
        #endif
    }

    /* Termina MPI */
    MPI_Finalize();
    
    return 0;
}

#else
/* Versao sequencial. */
int main(int argc, char *argv[]) {
    
    /* Imprime a saida? */
    int imprime = 0;
    
    /* Variaveis para arquivo. */
    int start, end, tamArq;
    
    /* Variaveis para o problema. */
    int valorPalavra, i=0, j=0, tam, tamfrases;
    char *palavra, **frases, **palavras; 
    int verif; 
    int countPalindromos = 0, countFrasesPalindromos = 0, countPrimos = 0, countFrases = 0, countPalavras = 0;
    int * primos, tamprimos;
    FILE *fp;
    
    /* Variaveis para contagem de tempo. */
    double time_proc_i = 0, time_proc_f, time_proc = 0;
    
    #ifdef TEMPOS_DETALHADOS
    double time_palin_pala_i = 0, time_palin_pala_f, time_palin_pala = 0;
    double time_palin_frase_i = 0, time_palin_frase_f, time_palin_frase = 0;
    double time_primo_i = 0, time_primo_f, time_primo = 0;
    double time_arq_i = 0, time_arq_f, time_arq = 0;
    #endif
    
    /* Verifica argumentos */
    if(argc < 4 || argc > 4) {
        printf("Uso: %s <arquivo de entrada> <metodo de analise> <imprime a saida?>\n", argv[0]);
        printf("<metodo de analise> = 1   --> leitura de palavras\n");
        printf("<metodo de analise> = 2   --> leitura de palavras e frases\n");
        printf("<imprime a saida?> = 1 para imprimir ou 0 para nao imprimir.\n");
        return 1;
    }
    
    imprime = atoi(argv[3]);
    
    if(imprime != 0 && imprime != 1) {
        fprintf(stderr, "Parametro incorreto para argumento 4.\n");
        return 1;
    }
    
    /* Inicia contagem do tempo. */
    time_proc_i = MPI_Wtime();
    
    /* Carrega arquivo. */
    fp = fopen(argv[1],"r");
    
    if(fp == NULL) {
        fprintf(stderr, "Erro na abertura do arquivo. Verifique se o arquivo existe ou se o direitorio esta correto.\n");
        MPI_Finalize();
        return 1;
    }
    
    tamArq = (int)fileSize(fp);
    
    /* Carrega arquivo em memoria principal de uma vez soh (mais rapido do que leituras aos poucos). */
    #ifdef TEMPOS_DETALHADOS
    time_arq_i = MPI_Wtime();
    #endif
    
    char * buffer = (char *)calloc(tamArq+1,sizeof(char));
    
    if(buffer == NULL) {
        fprintf(stderr, "Impossivel alocar copia do arquivo em memoria principal!\n");
        return 1;
    }
    
    fread(buffer, sizeof(char), tamArq, fp);
    
    buffer[tamArq] = '\0';
    
    fclose(fp);
    
    #ifdef TEMPOS_DETALHADOS
    time_arq_f = MPI_Wtime();
    time_arq += time_arq_f - time_arq_i;
    #endif
    
    /* Execucao para modo 1. */
    if(atoi(argv[2]) == 1) {   
        
        /* Calcula intervalos do arquivo... */
        start = 0;
        end = tamArq;
        
        #ifdef TEMPOS_DETALHADOS
        time_primo_i = MPI_Wtime();
        #endif
        
        /* Prepara vetor de primos */
        primos = calcPrimos(1000);
        tamprimos = 1000;
        
        #ifdef TEMPOS_DETALHADOS
        time_primo_f = MPI_Wtime();
        time_primo += time_primo_f - time_primo_i;
        
        time_arq_i = MPI_Wtime();
        #endif
          
        /* Gera vetor de ponteiros para strings contendo as palavras. */
        palavras = parseProxPalavras(buffer, tamArq, &start, end, &tam);
        
        #ifdef TEMPOS_DETALHADOS
        time_arq_f = MPI_Wtime();
        time_arq += time_arq_f - time_arq_i;
        #endif     
        
        /* Faz computacao */
        for(i = 0; i < tam; i++) {
            
            #ifdef TEMPOS_DETALHADOS
            time_palin_pala_i = MPI_Wtime();
            #endif
            
            verif = verificaPalindromo(palavras[i]);
            
            #ifdef TEMPOS_DETALHADOS
            time_palin_pala_f = MPI_Wtime();
            time_palin_pala += time_palin_pala_f - time_palin_pala_i;
            #endif
            
            if(verif) {
                countPalindromos++;
                
                #ifdef TEMPOS_DETALHADOS
                time_primo_i = MPI_Wtime();
                #endif
                
                valorPalavra = convertePalavraInteiro(palavras[i]);
                
                verif = verificaPrimo(&primos, &tamprimos, valorPalavra);
                
                #ifdef TEMPOS_DETALHADOS
                time_primo_f = MPI_Wtime();
                time_primo += time_primo_f - time_primo_i;
                #endif
                
                if(verif) {
                    countPrimos++;
                }
                
                if(imprime) {
                    printf("%s -- %d %s e primo.\n", palavras[i], valorPalavra, (verif) ? " ":"nao");
                }
            }
            
        }
        
        free(palavras);
        
        countPalavras += tam;
        
        free(primos);
        
    }

    /* Execucao para modo 2. */
    else if(atoi(argv[2]) == 2) {
        /* Calcula intervalos do arquivo... */
        start = 0;
        end = tamArq;
        
        #ifdef TEMPOS_DETALHADOS
        time_arq_i = MPI_Wtime();
        #endif
        
        /* Gera vetor de ponteiros para strigns contendo as frases. */
        frases = parseProxFrases(buffer, tamArq, start, end, &tamfrases);
        
        #ifdef TEMPOS_DETALHADOS
        time_arq_f = MPI_Wtime();
        time_arq += time_arq_f - time_arq_i;
        #endif
        
        countFrases = tamfrases;

        for(i = 0; i < tamfrases; i++) {
            
            #ifdef TEMPOS_DETALHADOS
            time_palin_frase_i = MPI_Wtime();
            #endif
            
            verif = verificaPalindromo(frases[i]);
            
            #ifdef TEMPOS_DETALHADOS
            time_palin_frase_f = MPI_Wtime();
            
            time_palin_frase += time_palin_frase_f - time_palin_frase_i;
            #endif
            
            if(verif) {
                countFrasesPalindromos++;
            }
            
            if(verif)
                if(imprime) {
                    printf("%s - palindromo frase.\n", frases[i]);
                }
                
                /* Copia palavras de uma frase em um vetor de strings. */
                #ifdef TEMPOS_DETALHADOS
                time_arq_i = MPI_Wtime(); 
                #endif
                
                palavras = parsePalavraFrase(frases[i], &tam);
                
                #ifdef TEMPOS_DETALHADOS
                time_arq_f = MPI_Wtime();
                
                time_arq += time_arq_f - time_arq_i;
                #endif
                
                for(j = 0; j < tam; j++) {
                    palavra = palavras[j];
                    
                    #ifdef TEMPOS_DETALHADOS
                    time_palin_pala_i = MPI_Wtime();
                    #endif
                    
                    verif = verificaPalindromo(palavra);
                    
                    #ifdef TEMPOS_DETALHADOS
                    time_palin_pala_f = MPI_Wtime();
                    
                    time_palin_pala += time_palin_pala_f - time_palin_pala_i;
                    #endif
                    
                    if(verif) {
                        countPalindromos++;
                    }
                    
                    
                    if(verif)
                        if(imprime) {
                            printf("%s -- e palindromo palavra\n", palavras[j]);
                        }
                }
                
                countPalavras += tam;
                
                free(palavras);
        }   
        
        free(frases);            
    }
    
    /* Tempo final */
    time_proc_f = MPI_Wtime();
    time_proc = time_proc_f - time_proc_i;
    
    /* Libera buffer do arquivo na memoria principal. */
    free(buffer);
        
    /* Imprime resultados obtidos... */
    fprintf(stderr, "Resultado\nPalavras processadas: %d\nFrases processadas: %d\nPalindromos encontrados: %d\nPrimos encontrados: %d\nNumero de frases palindromos encontrado: %d\n\nTempo total: %lf ms\n", countPalavras, countFrases, countPalindromos, countPrimos, countFrasesPalindromos, time_proc*1000.0f);
    
    #ifdef TEMPOS_DETALHADOS
    fprintf(stderr, "Tempo de calculo dos palindromos de palavras: %lf ms\nTempo de calculo dos palindromos de frases: %lf ms\nTempo de calculo dos primos: %lf ms\nTempo do processamento de buffers e arquivos: %lf ms\n", time_palin_pala*1000.0f, time_palin_frase*1000.0f, time_primo*1000.0f, time_arq*1000.0f);
    #endif
    
    return 0;
}
#endif
